home *** CD-ROM | disk | FTP | other *** search
/ The Utilities Experience / The Utilities Experience - Volume 1.iso / software / comms / term / extras / hydracom / hydracom-source.lha / amiga.c < prev    next >
C/C++ Source or Header  |  1996-02-04  |  57KB  |  2,633 lines

  1. /*
  2. **    Amiga support module for HYDRA protocol sample implementation.
  3. **
  4. **    Written by    Olaf Barthel
  5. **            Brabeckstrasse 35
  6. **            D-30559 Hannover
  7. **
  8. **            eMail: olsen@sourcery.han.de
  9. **
  10. **    Freely distributable.
  11. */
  12.  
  13.     /* System includes. */
  14.  
  15. #include <intuition/intuitionbase.h>
  16.  
  17. #include <libraries/gadtools.h>
  18. #include <libraries/locale.h>
  19. #include <libraries/asl.h>
  20.  
  21. #include <graphics/gfxbase.h>
  22.  
  23. #include <utility/date.h>
  24.  
  25. #include <devices/conunit.h>
  26. #include <devices/serial.h>
  27. #include <devices/timer.h>
  28.  
  29. #include <hardware/cia.h>
  30.  
  31. #include <dos/dosextens.h>
  32. #include <dos/filehandler.h>
  33. #include <dos/dostags.h>
  34. #include <dos/dosasl.h>
  35.  
  36. #include <exec/memory.h>
  37.  
  38.     /* Correct a nasty bug in the prototypes. */
  39.  
  40. #define CheckIO foo21234
  41.  
  42. #include <clib/intuition_protos.h>
  43. #include <clib/gadtools_protos.h>
  44. #include <clib/graphics_protos.h>
  45. #include <clib/utility_protos.h>
  46. #include <clib/locale_protos.h>
  47. #include <clib/timer_protos.h>
  48. #include <clib/exec_protos.h>
  49. #include <clib/dos_protos.h>
  50. #include <clib/asl_protos.h>
  51. #include <clib/macros.h>
  52.  
  53. #include <pragmas/intuition_pragmas.h>
  54. #include <pragmas/gadtools_pragmas.h>
  55. #include <pragmas/graphics_pragmas.h>
  56. #include <pragmas/utility_pragmas.h>
  57. #include <pragmas/locale_pragmas.h>
  58. #include <pragmas/timer_pragmas.h>
  59. #include <pragmas/exec_pragmas.h>
  60. #include <pragmas/dos_pragmas.h>
  61. #include <pragmas/asl_pragmas.h>
  62.  
  63. extern struct ExecBase        *SysBase;
  64. extern struct DosLibrary    *DOSBase;
  65.  
  66. #include <errno.h>
  67.  
  68. //#define DB(x)    x
  69. #define DB(x)
  70.  
  71. void __stdargs kprintf(STRPTR,...);
  72.  
  73.     /* Get the CheckIO prototype right. */
  74.  
  75. #undef CheckIO
  76.  
  77. struct IORequest *CheckIO(struct IORequest *);
  78.  
  79. #include "Rendezvous.h"
  80.  
  81. #include "hydracom.h"
  82.  
  83.     /* Difference between UTC and Amiga time. */
  84.  
  85. #define UTC_OFFSET    252482400
  86.  
  87.     /* Minimum of lines to reserve for local input. */
  88.  
  89. #define MIN_LINES    3
  90.  
  91.     /* Serial buffer size. */
  92.  
  93. #define BUFFER_SIZE    8192
  94.  
  95.     /* A handy macro. */
  96.  
  97. #define ClrSignal(s)    SetSignal(0,s)
  98.  
  99.     /* Signal masks. */
  100.  
  101. #define SIG_SERREAD    (1UL << ReadPort -> mp_SigBit)
  102. #define SIG_SERWRITE    (1UL << WritePort -> mp_SigBit)
  103. #define SIG_CONREAD    (1UL << ConsoleReadPort -> mp_SigBit)
  104. #define SIG_TIMER    (1UL << TimePort -> mp_SigBit)
  105. #define SIG_WINDOW    (1UL << WindowPort -> mp_SigBit)
  106. #define SIG_HANDSHAKE    SIGF_SINGLE
  107. #define SIG_KILL    SIGBREAKF_CTRL_C
  108.  
  109.     /* A serial buffer structure. */
  110.  
  111. struct SerialBuffer
  112. {
  113.     struct IOExtSer    *SerialRequest;
  114.     UBYTE        *SerialBuffer,
  115.             *SerialIndex,
  116.             *SerialTop;
  117.     LONG         SerialSize,
  118.              SerialFilled;
  119.     BOOL         IsClone,
  120.              IsBusy;
  121. };
  122.  
  123.     /* Special rendezvous data. */
  124.  
  125. STATIC struct RendezvousData        *RendezvousData;
  126. STATIC struct RendezvousSemaphore    *RendezvousSemaphore;
  127.  
  128.     /* Library bases. */
  129.  
  130. struct IntuitionBase    *IntuitionBase;
  131. struct GfxBase        *GfxBase;
  132. struct LocaleBase    *LocaleBase;
  133. struct Library        *GadToolsBase,
  134.             *UtilityBase,
  135.             *TimerBase,
  136.             *AslBase;
  137.  
  138.     /* Timer data. */
  139.  
  140. struct MsgPort        *TimePort;
  141. struct timerequest    *TimeRequest;
  142.  
  143.     /* Serial data. */
  144.  
  145. struct MsgPort        *ReadPort,
  146.             *WritePort;
  147.  
  148. struct SerialBuffer    *ThisBuffer,
  149.             *NextBuffer,
  150.             *ReadBuffer;
  151.  
  152.     /* Console data. */
  153.  
  154. struct MsgPort        *WindowPort;
  155.  
  156. struct Window        *FileWindow,
  157.             *RemoteWindow,
  158.             *LocalWindow,
  159.             *LogWindow;
  160.  
  161. struct MsgPort        *ConsoleWritePort,
  162.             *ConsoleReadPort;
  163. struct IOStdReq        *ConsoleReadRequest;
  164. UBYTE             ConsoleChar;
  165. BOOL             ConsoleReady = FALSE,
  166.              WindowReady = FALSE;
  167.  
  168. struct IOStdReq        *FileRequest,
  169.             *RemoteRequest,
  170.             *LocalRequest,
  171.             *LogRequest;
  172.  
  173.     /* DOS Data. */
  174.  
  175. struct Process        *ThisProcess;
  176. APTR             OldPtr;
  177. LONG             OldPri;
  178.  
  179. struct AnchorPath    *Anchor;
  180. BOOL             AnchorUsed = FALSE;
  181.  
  182.     /* File requester data. */
  183.  
  184. struct Process        *FileRequesterProcess;
  185. struct MsgPort        *FileRequesterPort;
  186.  
  187.     /* Screen data. */
  188.  
  189. struct Screen        *PublicScreen,
  190.             *Screen;
  191.  
  192.     /* Menu data. */
  193.  
  194. APTR             VisualInfo;
  195. struct Menu        *Menu;
  196.  
  197. struct NewMenu MenuTemplate[] =
  198. {
  199.     { NM_TITLE, "Project",             0 ,    0,    0,    (APTR)0},
  200.     {  NM_ITEM, "Toggle chat",        "C",    0,    0,    (APTR)Alt_C},
  201.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  202.     {  NM_ITEM, "Hang up",            "H",    0,    0,    (APTR)Alt_H},
  203.     {  NM_ITEM, "Toggle duplex",        "E",    0,    0,    (APTR)Alt_E},
  204.     {  NM_ITEM, "Toggle 7 bits/8 bits",    "B",    0,    0,    (APTR)Alt_B},
  205.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  206.     {  NM_ITEM, "Start upload",        "U",    0,    0,    (APTR)PgUp},
  207.     {  NM_ITEM, "Start download",        "D",    0,    0,    (APTR)PgDn},
  208.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  209.     {  NM_ITEM, "Abort Hydra session",    ".",    0,    0,    (APTR)Esc},
  210.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  211.     {  NM_ITEM, "Exit HydraCom",        "Q",    0,    0,    (APTR)Alt_X},
  212.     { NM_END,   0,                 0 ,    0,    0,    (APTR)0}
  213. };
  214.  
  215.     /* Time data. */
  216.  
  217. LONG             GMT_Offset = UTC_OFFSET;
  218.  
  219.     /* Version ID. */
  220.  
  221. STRPTR VersionTag = "$VER: hydracom 1.0r7 (15.12.95)\r\n";
  222.  
  223.     /* CloseWindowSafely(struct Window *Window):
  224.      *
  225.      *    Close a window sharing its UserPort with other
  226.      *    windows.
  227.      */
  228.  
  229. STATIC VOID
  230. CloseWindowSafely(struct Window *Window)
  231. {
  232.     struct IntuiMessage    *IntuiMessage;
  233.     struct Node        *Successor;
  234.  
  235.     Forbid();
  236.  
  237.     if(Window -> UserPort)
  238.     {
  239.         IntuiMessage = (struct IntuiMessage *)Window -> UserPort -> mp_MsgList . lh_Head;
  240.  
  241.         while(Successor = IntuiMessage -> ExecMessage . mn_Node . ln_Succ)
  242.         {
  243.             if(IntuiMessage -> IDCMPWindow == Window)
  244.             {
  245.                 Remove((struct Node *)IntuiMessage);
  246.  
  247.                 ReplyMsg((struct Message *)IntuiMessage);
  248.             }
  249.  
  250.             IntuiMessage = (struct IntuiMessage *)Successor;
  251.         }
  252.  
  253.         Window -> UserPort = NULL;
  254.     }
  255.  
  256.     ModifyIDCMP(Window,NULL);
  257.  
  258.     Permit();
  259.  
  260.     CloseWindow(Window);
  261. }
  262.  
  263.     /* UpdateTime(struct timeval *Now):
  264.      *
  265.      *    Get the current time and/or update the current
  266.      *    time offset data.
  267.      */
  268.  
  269. STATIC VOID
  270. UpdateTime(struct timeval *Now)
  271. {
  272.     if(Now)
  273.         Now -> tv_secs = Now -> tv_micro = 0;
  274.  
  275.     if(TimePort = CreateMsgPort())
  276.     {
  277.         if(TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest)))
  278.         {
  279.             if(!OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,NULL))
  280.             {
  281.                 TimerBase = (struct Library *)TimeRequest -> tr_node . io_Device;
  282.  
  283.                 if(LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38))
  284.                 {
  285.                     struct Locale *Locale;
  286.  
  287.                     if(Locale = OpenLocale(NULL))
  288.                     {
  289.                         GMT_Offset = 60 * Locale -> loc_GMTOffset + UTC_OFFSET;
  290.  
  291.                         CloseLocale(Locale);
  292.                     }
  293.  
  294.                     CloseLibrary(LocaleBase);
  295.  
  296.                     LocaleBase = NULL;
  297.                 }
  298.  
  299.                 if(Now)
  300.                     GetSysTime(Now);
  301.  
  302.                 TimerBase = NULL;
  303.  
  304.                 CloseDevice(TimeRequest);
  305.             }
  306.  
  307.             DeleteIORequest(TimeRequest);
  308.  
  309.             TimeRequest = NULL;
  310.         }
  311.  
  312.         DeleteMsgPort(TimePort);
  313.  
  314.         TimePort = NULL;
  315.     }
  316. }
  317.  
  318.     /* FileRequestEntry(VOID):
  319.      *
  320.      *    Asynchronous file request process entry.
  321.      */
  322.  
  323. STATIC VOID
  324. FileRequestEntry(VOID)
  325. {
  326.     struct FileRequester *FileRequester;
  327.  
  328.     geta4();
  329.  
  330.     if(FileRequester = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest,
  331.         ASLFR_TitleText,    "Select file(s) to upload",
  332.         ASLFR_InitialPattern,    "#?",
  333.         ASLFR_Flags1,        FRF_PRIVATEIDCMP | FRF_DOMULTISELECT | FRF_DOPATTERNS,
  334.     TAG_DONE))
  335.     {
  336.         if(FileRequesterPort = CreateMsgPort())
  337.         {
  338.             struct Message    *Message;
  339.             ULONG         Signals;
  340.             BOOL         Done = FALSE;
  341.  
  342.             FileRequesterProcess = (struct Process *)FindTask(NULL);
  343.  
  344.             Signal(ThisProcess,SIG_HANDSHAKE);
  345.  
  346.             do
  347.             {
  348.                 Signals = Wait((1L << FileRequesterPort -> mp_SigBit) | SIG_KILL);
  349.  
  350.                 if(Signals & (1L << FileRequesterPort -> mp_SigBit))
  351.                 {
  352.                     LONG MaxLen;
  353.  
  354.                     while(Message = GetMsg(FileRequesterPort))
  355.                     {
  356.                         MaxLen = (LONG)Message -> mn_Node . ln_Name;
  357.  
  358.                         if(AslRequestTags(FileRequester,
  359.                             ASLFR_Window,        LocalWindow,
  360.                             ASLFR_SleepWindow,    TRUE,
  361.                         TAG_DONE))
  362.                         {
  363.                             if(FileRequester -> fr_NumArgs > 0)
  364.                             {
  365.                                 UBYTE     LocalBuffer[256];
  366.                                 char    *String;
  367.                                 LONG     Len,Count,i;
  368.  
  369.                                 for(i = Len = 0 ; i < FileRequester -> fr_NumArgs ; i++)
  370.                                 {
  371.                                     if(FileRequester -> fr_ArgList[i] . wa_Lock)
  372.                                     {
  373.                                         if(NameFromLock(FileRequester -> fr_ArgList[i] . wa_Lock,LocalBuffer,256))
  374.                                             Len += strlen(LocalBuffer) + 1;
  375.                                     }
  376.                                     else
  377.                                         Len += strlen(FileRequester -> fr_Drawer) + 1;
  378.  
  379.                                     Len += strlen(FileRequester -> fr_ArgList[i] . wa_Name) + 1 + 2;
  380.                                 }
  381.  
  382.                                 Len++;
  383.  
  384.                                 if(String = AllocVec(Len,MEMF_ANY))
  385.                                 {
  386.                                     *String = 0;
  387.  
  388.                                     for(i = Count = 0 ; Count < MaxLen && i < FileRequester -> fr_NumArgs ; i++)
  389.                                     {
  390.                                         if(FileRequester -> fr_ArgList[i] . wa_Lock)
  391.                                         {
  392.                                             if(NameFromLock(FileRequester -> fr_ArgList[i] . wa_Lock,LocalBuffer,256))
  393.                                             {
  394.                                                 if(AddPart(LocalBuffer,FileRequester -> fr_ArgList[i] . wa_Name,256))
  395.                                                 {
  396.                                                     if(Count + strlen(LocalBuffer) + 2 < MaxLen)
  397.                                                     {
  398.                                                         strcat(String,"\"");
  399.                                                         strcat(String,LocalBuffer);
  400.                                                         strcat(String,"\"");
  401.  
  402.                                                         Count += strlen(LocalBuffer) + 2;
  403.                                                     }
  404.                                                     else
  405.                                                         break;
  406.                                                 }
  407.                                             }
  408.                                         }
  409.                                         else
  410.                                         {
  411.                                             strcpy(LocalBuffer,FileRequester -> fr_Drawer);
  412.  
  413.                                             if(AddPart(LocalBuffer,FileRequester -> fr_ArgList[i] . wa_Name,256))
  414.                                             {
  415.                                                 if(Count + strlen(LocalBuffer) + 2 < MaxLen)
  416.                                                 {
  417.                                                     strcat(String,"\"");
  418.                                                     strcat(String,LocalBuffer);
  419.                                                     strcat(String,"\"");
  420.  
  421.                                                     Count += strlen(LocalBuffer) + 2;
  422.                                                 }
  423.                                                 else
  424.                                                     break;
  425.                                             }
  426.                                         }
  427.  
  428.                                         if(i != FileRequester -> fr_NumArgs - 1)
  429.                                         {
  430.                                             strcat(String," ");
  431.                                             Count++;
  432.                                         }
  433.                                     }
  434.  
  435.                                     Message -> mn_Node . ln_Name = String;
  436.  
  437.                                     ReplyMsg(Message);
  438.  
  439.                                     Message = NULL;
  440.                                 }
  441.                             }
  442.                             else
  443.                             {
  444.                                 if(FileRequester -> fr_File[0])
  445.                                 {
  446.                                     LONG Len;
  447.  
  448.                                     Len = strlen(FileRequester -> fr_Drawer) + strlen(FileRequester -> fr_File) + 2 + 2;
  449.  
  450.                                     if(Len <= MaxLen)
  451.                                     {
  452.                                         char *String;
  453.  
  454.                                         if(String = AllocVec(Len,MEMF_ANY))
  455.                                         {
  456.                                             strcpy(String + 1,FileRequester -> fr_Drawer);
  457.  
  458.                                             if(AddPart(String + 1,FileRequester -> fr_File,Len))
  459.                                             {
  460.                                                 String[0] = '\"';
  461.                                                 strcat(String,"\"");
  462.  
  463.                                                 Message -> mn_Node . ln_Name = String;
  464.  
  465.                                                 ReplyMsg(Message);
  466.  
  467.                                                 Message = NULL;
  468.                                             }
  469.                                             else
  470.                                                 FreeVec(String);
  471.                                         }
  472.                                     }
  473.                                 }
  474.                             }
  475.                         }
  476.  
  477.                         if(Message)
  478.                         {
  479.                             Message -> mn_Node . ln_Name = NULL;
  480.  
  481.                             ReplyMsg(Message);
  482.                         }
  483.                     }
  484.                 }
  485.  
  486.                 if(Signals & SIG_KILL)
  487.                     Done = TRUE;
  488.             }
  489.             while(!Done);
  490.  
  491.             while(Message = GetMsg(FileRequesterPort))
  492.             {
  493.                 Message -> mn_Node . ln_Name = NULL;
  494.  
  495.                 ReplyMsg(Message);
  496.             }
  497.  
  498.             DeleteMsgPort(FileRequesterPort);
  499.         }
  500.  
  501.         FreeAslRequest(FileRequester);
  502.     }
  503.  
  504.     Forbid();
  505.  
  506.     FileRequesterProcess = NULL;
  507.  
  508.     Signal(ThisProcess,SIG_HANDSHAKE);
  509. }
  510.  
  511.     /* GetFiles(char *Buffer,int MaxLen):
  512.      *
  513.      *    Get a list of file names, asynchronously please.
  514.      */
  515.  
  516. char *
  517. GetFiles(char *Buffer,int MaxLen)
  518. {
  519.     struct MsgPort    *ReplyPort;
  520.     char        *Result = NULL;
  521.  
  522.     if(ReplyPort = CreateMsgPort())
  523.     {
  524.         struct Message *Message;
  525.  
  526.         if(Message = AllocVec(sizeof(struct Message),MEMF_ANY | MEMF_CLEAR))
  527.         {
  528.             Message -> mn_Length        = sizeof(struct Message);
  529.             Message -> mn_ReplyPort        = ReplyPort;
  530.             Message -> mn_Node . ln_Name    = (STRPTR)MaxLen;
  531.  
  532.             PutMsg(FileRequesterPort,Message);
  533.  
  534.             FOREVER
  535.             {
  536.                 if(SetSignal(0,(1L << ReplyPort -> mp_SigBit)) & (1L << ReplyPort -> mp_SigBit))
  537.                 {
  538.                     GetMsg(ReplyPort);
  539.  
  540.                     break;
  541.                 }
  542.  
  543.                 sys_idle();
  544.             }
  545.  
  546.             if(Message -> mn_Node . ln_Name)
  547.             {
  548.                 strcpy(Buffer,Message -> mn_Node . ln_Name);
  549.  
  550.                 FreeVec(Message -> mn_Node . ln_Name);
  551.  
  552.                 Result = Buffer;
  553.             }
  554.  
  555.             FreeVec(Message);
  556.         }
  557.  
  558.         DeleteMsgPort(ReplyPort);
  559.     }
  560.  
  561.     return(Result);
  562. }
  563.  
  564.     /* OpenConsole():
  565.      *
  566.      *    Open a console window.
  567.      */
  568.  
  569. STATIC BOOL
  570. OpenConsole(struct Screen *Screen,LONG Top,LONG Height,STRPTR Title,BOOL Resize,struct Window **WindowPtr,struct IOStdReq **ConsolePtr)
  571. {
  572.     struct Window *Window;
  573.  
  574.     if(Window = OpenWindowTags(NULL,
  575.         WA_Left,        0,
  576.         WA_Top,            Top,
  577.         WA_Width,        Screen -> Width,
  578.         WA_Height,        Height,
  579.         WA_Title,        Title,
  580.         WA_SimpleRefresh,    TRUE,
  581.         WA_DepthGadget,        TRUE,
  582.         WA_DragBar,        TRUE,
  583.         WA_SizeGadget,        Resize,
  584.         WA_SizeBRight,        TRUE,
  585.         WA_CustomScreen,    Screen,
  586.         WA_NewLookMenus,    TRUE,
  587.     TAG_DONE))
  588.     {
  589.         Window -> UserPort = WindowPort;
  590.  
  591.         SetMenuStrip(Window,Menu);
  592.  
  593.         if(ModifyIDCMP(Window,IDCMP_MENUPICK))
  594.         {
  595.             struct IOStdReq *ConsoleRequest;
  596.  
  597.             if(Window -> RPort -> Font -> tf_Flags & FPF_PROPORTIONAL)
  598.                 SetFont(Window -> RPort,GfxBase -> DefaultFont);
  599.  
  600.             if(ConsoleRequest = (struct IOStdReq *)CreateIORequest(ConsoleWritePort,sizeof(struct IOStdReq)))
  601.             {
  602.                 ConsoleRequest -> io_Data = Window;
  603.  
  604.                 if(!OpenDevice("console.device",CONU_CHARMAP,ConsoleRequest,CONFLAG_DEFAULT))
  605.                 {
  606.                     WindowLimits(Window,Window -> BorderLeft + 10 * Window -> RPort -> Font -> tf_XSize * 10 + Window -> BorderRight,Window -> BorderTop + 2 * Window -> RPort -> Font -> tf_YSize + Window -> BorderBottom,Screen -> Width,Screen -> Height);
  607.  
  608.                         /* Turn off the cursor. */
  609.  
  610.                     ConPrintf(ConsoleRequest,"\033[0 p");
  611.  
  612.                     *WindowPtr    = Window;
  613.                     *ConsolePtr    = ConsoleRequest;
  614.  
  615.                     return(TRUE);
  616.                 }
  617.  
  618.                 DeleteIORequest(ConsoleRequest);
  619.             }
  620.         }
  621.  
  622.         ClearMenuStrip(Window);
  623.  
  624.         CloseWindowSafely(Window);
  625.     }
  626.  
  627.     return(FALSE);
  628. }
  629.  
  630.     /* CloseConsole():
  631.      *
  632.      *    Close a console window.
  633.      */
  634.  
  635. STATIC VOID
  636. CloseConsole(struct Window **WindowPtr,struct IOStdReq **ConsolePtr)
  637. {
  638.     if(*ConsolePtr)
  639.     {
  640.         CloseDevice(*ConsolePtr);
  641.  
  642.         DeleteIORequest(*ConsolePtr);
  643.  
  644.         *ConsolePtr = NULL;
  645.     }
  646.  
  647.     if(*WindowPtr)
  648.     {
  649.         ClearMenuStrip(*WindowPtr);
  650.  
  651.         CloseWindowSafely(*WindowPtr);
  652.  
  653.         *WindowPtr = NULL;
  654.     }
  655. }
  656.  
  657.     /* CloneSerialBuffer():
  658.      *
  659.      *    Clone a SerialBuffer structure.
  660.      */
  661.  
  662. STATIC struct SerialBuffer *
  663. CloneSerialBuffer(struct SerialBuffer *Source,struct MsgPort *MsgPort)
  664. {
  665.     struct SerialBuffer *Buffer;
  666.  
  667.     if(Buffer = (struct SerialBuffer *)AllocVec(sizeof(struct SerialBuffer) + Source -> SerialSize,MEMF_ANY | MEMF_PUBLIC))
  668.     {
  669.         Buffer -> SerialBuffer    = Buffer -> SerialIndex = (UBYTE *)(Buffer + 1);
  670.         Buffer -> SerialFilled    = 0;
  671.         Buffer -> SerialTop    = Buffer -> SerialBuffer + Source -> SerialSize;
  672.         Buffer -> SerialSize    = Source -> SerialSize;
  673.         Buffer -> IsClone    = TRUE;
  674.         Buffer -> IsBusy    = FALSE;
  675.  
  676.         if(Buffer -> SerialRequest = (struct IOExtSer *)AllocVec(sizeof(struct IOExtSer),MEMF_ANY | MEMF_PUBLIC))
  677.         {
  678.             CopyMem(Source -> SerialRequest,Buffer -> SerialRequest,sizeof(struct IOExtSer));
  679.  
  680.             Buffer -> SerialRequest -> IOSer . io_Message . mn_ReplyPort = MsgPort;
  681.  
  682.             return(Buffer);
  683.         }
  684.         else
  685.             cprint("Could not create serial request\n");
  686.  
  687.         FreeVec(Buffer);
  688.     }
  689.     else
  690.         cprint("Could not create serial buffer\n");
  691.  
  692.     return(NULL);
  693. }
  694.  
  695.     /* DeleteSerialBuffer():
  696.      *
  697.      *    Delete a SerialBuffer structure.
  698.      */
  699.  
  700. STATIC VOID
  701. DeleteSerialBuffer(struct SerialBuffer *Buffer)
  702. {
  703.     if(Buffer)
  704.     {
  705.         if(Buffer -> IsBusy)
  706.         {
  707.             if(!CheckIO(Buffer -> SerialRequest))
  708.                 AbortIO(Buffer -> SerialRequest);
  709.  
  710.             WaitIO(Buffer -> SerialRequest);
  711.         }
  712.  
  713.         if(Buffer -> IsClone)
  714.             FreeVec(Buffer -> SerialRequest);
  715.         else
  716.         {
  717.             CloseDevice(Buffer -> SerialRequest);
  718.  
  719.             DeleteIORequest(Buffer -> SerialRequest);
  720.         }
  721.  
  722.         FreeVec(Buffer);
  723.     }
  724. }
  725.  
  726.     /* CreateSerialBuffer():
  727.      *
  728.      *    Create a serial buffer structure.
  729.      */
  730.  
  731. STATIC struct SerialBuffer *
  732. CreateSerialBuffer(STRPTR Device,LONG Unit,LONG Size,struct MsgPort *MsgPort)
  733. {
  734.     struct SerialBuffer *Buffer;
  735.  
  736.     if(Buffer = (struct SerialBuffer *)AllocVec(sizeof(struct SerialBuffer) + Size,MEMF_ANY | MEMF_PUBLIC))
  737.     {
  738.         Buffer -> SerialBuffer    = Buffer -> SerialIndex = (UBYTE *)(Buffer + 1);
  739.         Buffer -> SerialFilled    = 0;
  740.         Buffer -> SerialTop    = Buffer -> SerialBuffer + Size;
  741.         Buffer -> SerialSize    = Size;
  742.         Buffer -> IsClone    = FALSE;
  743.         Buffer -> IsBusy    = FALSE;
  744.  
  745.         if(Buffer -> SerialRequest = (struct IOExtSer *)CreateIORequest(MsgPort,sizeof(struct IOExtSer)))
  746.         {
  747.             Buffer -> SerialRequest -> io_SerFlags = SERF_SHARED|SERF_7WIRE;
  748.  
  749.             if(!OpenDevice(Device,Unit,Buffer -> SerialRequest,NULL))
  750.                 return(Buffer);
  751.             else
  752.             {
  753.                 cprint("Could not open \"%s\", unit %d\n",Device,Unit);
  754.  
  755.                 DeleteIORequest(Buffer -> SerialRequest);
  756.             }
  757.         }
  758.         else
  759.             cprint("Could not create serial request\n");
  760.  
  761.         FreeVec(Buffer);
  762.     }
  763.     else
  764.         cprint("Could not create serial buffer\n");
  765.  
  766.     return(NULL);
  767. }
  768.  
  769.     /* OpenAll():
  770.      *
  771.      *    Allocate all the resources required.
  772.      */
  773.  
  774. STATIC BOOL
  775. OpenAll(STRPTR Device,LONG Unit)
  776. {
  777.     LONG Top,Lines,BorderSize,FontSize,ExtraLines,RemainingLines,TotalHeight;
  778.     UWORD Pens = (UWORD)~0;
  779.  
  780.     ThisProcess = (struct Process *)FindTask(NULL);
  781.  
  782.     if(pri != 1000)
  783.     {
  784.         if(pri < -128)
  785.             pri = 128;
  786.         else
  787.         {
  788.             if(pri > 127)
  789.                 pri = 127;
  790.         }
  791.  
  792.         OldPri = SetTaskPri(ThisProcess,pri);
  793.     }
  794.  
  795.     if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37)))
  796.     {
  797.         cprint("Could not open intuition.library v37\n");
  798.  
  799.         return(FALSE);
  800.     }
  801.  
  802.     if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",37)))
  803.     {
  804.         cprint("Could not open graphics.library v37\n");
  805.  
  806.         return(FALSE);
  807.     }
  808.  
  809.     if(!(GadToolsBase = OpenLibrary("gadtools.library",37)))
  810.     {
  811.         cprint("Could not open gadtools.library v37\n");
  812.  
  813.         return(FALSE);
  814.     }
  815.  
  816.     if(!(UtilityBase = OpenLibrary("utility.library",37)))
  817.     {
  818.         cprint("Could not open utility.library v37\n");
  819.  
  820.         return(FALSE);
  821.     }
  822.  
  823.     if(!(AslBase = OpenLibrary("asl.library",37)))
  824.     {
  825.         cprint("Could not open asl.library v37\n");
  826.  
  827.         return(FALSE);
  828.     }
  829.  
  830.     if(LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38))
  831.     {
  832.         struct Locale *Locale;
  833.  
  834.         if(Locale = OpenLocale(NULL))
  835.         {
  836.             GMT_Offset = 60 * Locale -> loc_GMTOffset + UTC_OFFSET;
  837.  
  838.             CloseLocale(Locale);
  839.         }
  840.  
  841.         CloseLibrary(LocaleBase);
  842.     }
  843.  
  844.     Forbid();
  845.  
  846.     if(CreateNewProcTags(
  847.         NP_Name,    "HydraCom Filerequester Process",
  848.         NP_WindowPtr,    -1,
  849.         NP_Entry,    FileRequestEntry,
  850.     TAG_DONE))
  851.     {
  852.         ClrSignal(SIG_HANDSHAKE);
  853.  
  854.         Wait(SIG_HANDSHAKE);
  855.     }
  856.  
  857.     Permit();
  858.  
  859.     if(!FileRequesterProcess)
  860.     {
  861.         cprint("Could not create file requester process\n");
  862.  
  863.         return(FALSE);
  864.     }
  865.  
  866.     if(!(TimePort = CreateMsgPort()))
  867.     {
  868.         cprint("Could not create timer port\n");
  869.  
  870.         return(FALSE);
  871.     }
  872.  
  873.     if(!(TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest))))
  874.     {
  875.         cprint("Could not create timer request\n");
  876.  
  877.         return(FALSE);
  878.     }
  879.  
  880.     if(OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,NULL))
  881.     {
  882.         cprint("Could not open timer\n");
  883.  
  884.         return(FALSE);
  885.     }
  886.  
  887.     TimerBase = (struct Library *)TimeRequest -> tr_node . io_Device;
  888.  
  889.     if(!(Anchor = (struct AnchorPath *)AllocVec(sizeof(struct AnchorPath) + 512,MEMF_ANY | MEMF_CLEAR)))
  890.     {
  891.         cprint("Could not allocate pattern matching buffe\n");
  892.  
  893.         return(FALSE);
  894.     }
  895.  
  896.     Anchor -> ap_Strlen = 512;
  897.  
  898.     if(!(ReadPort = CreateMsgPort()))
  899.     {
  900.         cprint("Could not create serial read port\n");
  901.  
  902.         return(FALSE);
  903.     }
  904.  
  905.     if(!(WritePort = CreateMsgPort()))
  906.     {
  907.         cprint("Could not create serial write port\n");
  908.  
  909.         return(FALSE);
  910.     }
  911.  
  912.     Forbid();
  913.  
  914.     if(RendezvousSemaphore = (struct RendezvousSemaphore *)FindSemaphore(Device))
  915.     {
  916.         ObtainSemaphore(RendezvousSemaphore);
  917.  
  918.         if(!(RendezvousData = (*RendezvousSemaphore -> rs_Login)(ReadPort,WritePort,NULL)))
  919.         {
  920.             Permit();
  921.  
  922.             ReleaseSemaphore(RendezvousSemaphore);
  923.  
  924.             RendezvousSemaphore = NULL;
  925.  
  926.             cprint("Could not link to `term' port \"%s\"\n",Device);
  927.  
  928.             return(FALSE);
  929.         }
  930.     }
  931.  
  932.     Permit();
  933.  
  934.     if(!(ConsoleReadPort = CreateMsgPort()))
  935.     {
  936.         cprint("Could not create console read port\n");
  937.  
  938.         return(FALSE);
  939.     }
  940.  
  941.     if(!(ConsoleWritePort = CreateMsgPort()))
  942.     {
  943.         cprint("Could not create console write port\n");
  944.  
  945.         return(FALSE);
  946.     }
  947.  
  948.     if(!(ConsoleReadRequest = (struct IOStdReq *)AllocVec(sizeof(struct IOStdReq),MEMF_ANY | MEMF_PUBLIC | MEMF_CLEAR)))
  949.     {
  950.         cprint("Could not create console read request\n");
  951.  
  952.         return(FALSE);
  953.     }
  954.  
  955.     if(!RendezvousData)
  956.     {
  957.         if(!(ReadBuffer = CreateSerialBuffer(Device,Unit,BUFFER_SIZE,ReadPort)))
  958.             return(FALSE);
  959.     }
  960.     else
  961.     {
  962.         if(ReadBuffer = (struct SerialBuffer *)AllocVec(sizeof(struct SerialBuffer) + BUFFER_SIZE,MEMF_ANY | MEMF_PUBLIC))
  963.         {
  964.             ReadBuffer -> SerialBuffer    = ReadBuffer -> SerialIndex = (UBYTE *)(ReadBuffer + 1);
  965.             ReadBuffer -> SerialFilled    = 0;
  966.             ReadBuffer -> SerialTop        = ReadBuffer -> SerialBuffer + BUFFER_SIZE;
  967.             ReadBuffer -> SerialSize    = BUFFER_SIZE;
  968.             ReadBuffer -> IsClone        = TRUE;
  969.             ReadBuffer -> IsBusy        = FALSE;
  970.             ReadBuffer -> SerialRequest    = &RendezvousData -> rd_ReadRequest;
  971.  
  972.                 /* Ralph Seichter suggested reusing the data
  973.                  * stored in the rendezvous data.
  974.                  */
  975.  
  976.             com_speed = ReadBuffer -> SerialRequest -> io_Baud;
  977.  
  978.             if(cur_speed > com_speed)
  979.                 cur_speed = com_speed;
  980.  
  981.             if(ReadBuffer -> SerialRequest -> io_ReadLen == 7 && ReadBuffer -> SerialRequest -> io_WriteLen == 7 && (ReadBuffer -> SerialRequest -> io_SerFlags & (SERF_PARTY_ON|SERF_PARTY_ODD)) == SERF_PARTY_ON && !(ReadBuffer -> SerialRequest -> io_SerFlags & (SEXTF_MSPON|SEXTF_MARK)))
  982.             {
  983.                 parity = true;
  984.                 hydra_options |= HOPT_HIGHBIT;
  985.             }
  986.             else
  987.                 parity = false;
  988.         }
  989.         else
  990.         {
  991.             cprint("Could not create serial ReadBuffer\n");
  992.  
  993.             return(FALSE);
  994.         }
  995.     }
  996.  
  997.     if(!(ThisBuffer = CloneSerialBuffer(ReadBuffer,WritePort)))
  998.         return(FALSE);
  999.  
  1000.     if(!(NextBuffer = CloneSerialBuffer(ReadBuffer,WritePort)))
  1001.         return(FALSE);
  1002.  
  1003.     if(!(PublicScreen = LockPubScreen(NULL)))
  1004.     {
  1005.         cprint("Could not find default public screen\n");
  1006.  
  1007.         return(FALSE);
  1008.     }
  1009.  
  1010.     if(RendezvousData)
  1011.     {
  1012.         if(!(Screen = RendezvousData -> rd_Screen))
  1013.             Screen = PublicScreen;
  1014.     }
  1015.     else
  1016.     {
  1017.         if(!(Screen = OpenScreenTags(NULL,
  1018.             SA_DisplayID,    GetVPModeID(&PublicScreen -> ViewPort),
  1019.             SA_Overscan,    OSCAN_TEXT,
  1020.             SA_Depth,    2,
  1021.             SA_Title,    PRGNAME " " VERSION " " HC_OS " Amiga rev 6, ported by Olaf `Olsen' Barthel",
  1022.             SA_Behind,    TRUE,
  1023.             SA_SysFont,    1,
  1024.             SA_Pens,    &Pens,
  1025.             SA_Interleaved,    TRUE,
  1026.         TAG_DONE)))
  1027.         {
  1028.             cprint("Could not open screen\n");
  1029.  
  1030.             return(FALSE);
  1031.         }
  1032.     }
  1033.  
  1034.     if(!(VisualInfo = GetVisualInfo(Screen,TAG_DONE)))
  1035.     {
  1036.         cprint("Could not obtain screen visual info\n");
  1037.  
  1038.         return(FALSE);
  1039.     }
  1040.  
  1041.     if(!(Menu = CreateMenus(MenuTemplate,TAG_DONE)))
  1042.     {
  1043.         cprint("Could not create menus\n");
  1044.  
  1045.         return(FALSE);
  1046.     }
  1047.  
  1048.     if(!LayoutMenus(Menu,VisualInfo,
  1049.         GTMN_TextAttr,        Screen -> Font,
  1050.         GTMN_NewLookMenus,    TRUE,
  1051.     TAG_DONE))
  1052.     {
  1053.         cprint("Could not layout menus\n");
  1054.  
  1055.         return(FALSE);
  1056.     }
  1057.  
  1058.     Top        = Screen -> BarHeight + 1;
  1059.     BorderSize    = Screen -> WBorTop + Screen -> Font -> ta_YSize + 1 + Screen -> WBorBottom;
  1060.     FontSize    = GfxBase -> DefaultFont -> tf_YSize;
  1061.     TotalHeight    = Screen -> Height - Top;
  1062.     Lines        = (TotalHeight - 3 - 4 * BorderSize) / FontSize;
  1063.     ExtraLines    = Lines > MIN_LINES ? (Lines - MIN_LINES) / 3 : 0;
  1064.     RemainingLines    = Lines > MIN_LINES + ExtraLines * 3 ? Lines - (MIN_LINES + ExtraLines * 3) : 0;
  1065.  
  1066.     if(Lines < MIN_LINES)
  1067.     {
  1068.         cprint("Screen size too small (need at least %d text lines, can get only %d)\n",MIN_LINES,Lines);
  1069.  
  1070.         return(FALSE);
  1071.     }
  1072.  
  1073.     if(!(WindowPort = CreateMsgPort()))
  1074.     {
  1075.         cprint("Could not create window port\n");
  1076.  
  1077.         return(FALSE);
  1078.     }
  1079.  
  1080.     if(!OpenConsole(Screen,Top,BorderSize + (6 + ExtraLines) * FontSize,"Log",TRUE,&LogWindow,&LogRequest))
  1081.     {
  1082.         cprint("Could not open console window #1\n");
  1083.  
  1084.         return(FALSE);
  1085.     }
  1086.  
  1087.     TotalHeight    -= LogWindow -> Height + 1;
  1088.     Top        += LogWindow -> Height + 1;
  1089.  
  1090.     if(!OpenConsole(Screen,Top,BorderSize + 2 * FontSize,"File",FALSE,&FileWindow,&FileRequest))
  1091.     {
  1092.         cprint("Could not open console window #2\n");
  1093.  
  1094.         return(FALSE);
  1095.     }
  1096.  
  1097.     ConPrintf(FileRequest,"\033[?7l");
  1098.  
  1099.     TotalHeight    -= FileWindow -> Height + 1;
  1100.     Top        += FileWindow -> Height + 1;
  1101.  
  1102.     if(!OpenConsole(Screen,Top,BorderSize + (8 + RemainingLines) * FontSize,"Remote",TRUE,&RemoteWindow,&RemoteRequest))
  1103.     {
  1104.         cprint("Could not open console window #3\n");
  1105.  
  1106.         return(FALSE);
  1107.     }
  1108.  
  1109.     TotalHeight    -= RemoteWindow -> Height + 1;
  1110.     Top        += RemoteWindow -> Height + 1;
  1111.  
  1112.     if(!OpenConsole(Screen,Top,TotalHeight,"Local (Press [Amiga+C] to start/end chat mode, [Esc] to abort Hydra session)",TRUE,&LocalWindow,&LocalRequest))
  1113.     {
  1114.         cprint("Could not open console window #4\n");
  1115.  
  1116.         return(FALSE);
  1117.     }
  1118.  
  1119.     CopyMem(LocalRequest,ConsoleReadRequest,sizeof(struct IOStdReq));
  1120.  
  1121.     ConsoleReadRequest -> io_Message . mn_ReplyPort = ConsoleReadPort;
  1122.  
  1123.         /* Turn the cursors back on. */
  1124.  
  1125.     ConPrintf(LocalRequest,"\33[ p");
  1126.     ConPrintf(RemoteRequest,"\33[ p");
  1127.  
  1128.     ConsoleReadRequest -> io_Command    = CMD_READ;
  1129.     ConsoleReadRequest -> io_Data        = &ConsoleChar;
  1130.     ConsoleReadRequest -> io_Length        = 1;
  1131.  
  1132.     ClrSignal(SIG_CONREAD);
  1133.     SendIO(ConsoleReadRequest);
  1134.  
  1135.     OldPtr = ThisProcess -> pr_WindowPtr;
  1136.  
  1137.     ThisProcess -> pr_WindowPtr = (APTR)LocalWindow;
  1138.  
  1139.     if(!quiet)
  1140.     {
  1141.         ScreenToFront(Screen);
  1142.  
  1143.         ActivateWindow(LocalWindow);
  1144.     }
  1145.  
  1146.     UnlockPubScreen(NULL,PublicScreen);
  1147.  
  1148.     PublicScreen = NULL;
  1149.  
  1150.     if(!RendezvousData)
  1151.         com_flow(flowflags);
  1152.  
  1153.     return(TRUE);
  1154. }
  1155.  
  1156.     /* CloseAll():
  1157.      *
  1158.      *    Close all the resources.
  1159.      */
  1160.  
  1161. STATIC VOID
  1162. CloseAll(VOID)
  1163. {
  1164.     if(FileRequesterProcess)
  1165.     {
  1166.         Forbid();
  1167.  
  1168.         ClrSignal(SIG_HANDSHAKE);
  1169.  
  1170.         Signal(FileRequesterProcess,SIG_KILL);
  1171.  
  1172.         Wait(SIG_HANDSHAKE);
  1173.  
  1174.         Permit();
  1175.     }
  1176.  
  1177.     if(LocalWindow)
  1178.         ClearMenuStrip(LocalWindow);
  1179.  
  1180.     if(Menu)
  1181.         FreeMenus(Menu);
  1182.  
  1183.     if(VisualInfo)
  1184.         FreeVisualInfo(VisualInfo);
  1185.  
  1186.     if(AnchorUsed)
  1187.         MatchEnd(Anchor);
  1188.  
  1189.     if(Anchor)
  1190.         FreeVec(Anchor);
  1191.  
  1192.     if(ThisProcess)
  1193.         ThisProcess -> pr_WindowPtr = OldPtr;
  1194.  
  1195.     if(ConsoleReadRequest)
  1196.     {
  1197.         if(ConsoleReadRequest -> io_Device)
  1198.         {
  1199.             if(!CheckIO(ConsoleReadRequest))
  1200.                 AbortIO(ConsoleReadRequest);
  1201.  
  1202.             WaitIO(ConsoleReadRequest);
  1203.         }
  1204.  
  1205.         FreeVec(ConsoleReadRequest);
  1206.     }
  1207.  
  1208.     CloseConsole(&LocalWindow,&LocalRequest);
  1209.     CloseConsole(&RemoteWindow,&RemoteRequest);
  1210.     CloseConsole(&FileWindow,&FileRequest);
  1211.     CloseConsole(&LogWindow,&LogRequest);
  1212.  
  1213.     if(WindowPort)
  1214.         DeleteMsgPort(WindowPort);
  1215.  
  1216.     if(!RendezvousData && Screen)
  1217.         CloseScreen(Screen);
  1218.  
  1219.     if(PublicScreen)
  1220.         UnlockPubScreen(NULL,PublicScreen);
  1221.  
  1222.     DeleteSerialBuffer(NextBuffer);
  1223.     DeleteSerialBuffer(ThisBuffer);
  1224.  
  1225.     if(RendezvousData)
  1226.     {
  1227.         if(ReadBuffer -> IsBusy)
  1228.         {
  1229.             if(!CheckIO(ReadBuffer -> SerialRequest))
  1230.                 AbortIO(ReadBuffer -> SerialRequest);
  1231.  
  1232.             WaitIO(ReadBuffer -> SerialRequest);
  1233.         }
  1234.  
  1235.         FreeVec(ReadBuffer);
  1236.     }
  1237.     else
  1238.         DeleteSerialBuffer(ReadBuffer);
  1239.  
  1240.     if(ConsoleWritePort)
  1241.         DeleteMsgPort(ConsoleWritePort);
  1242.  
  1243.     if(ConsoleReadPort)
  1244.         DeleteMsgPort(ConsoleReadPort);
  1245.  
  1246.     if(WritePort)
  1247.         DeleteMsgPort(WritePort);
  1248.  
  1249.     if(ReadPort)
  1250.         DeleteMsgPort(ReadPort);
  1251.  
  1252.     if(TimeRequest)
  1253.     {
  1254.         if(TimeRequest -> tr_node . io_Device)
  1255.             CloseDevice(TimeRequest);
  1256.  
  1257.         DeleteIORequest(TimeRequest);
  1258.     }
  1259.  
  1260.     if(TimePort)
  1261.         DeleteMsgPort(TimePort);
  1262.  
  1263.     if(UtilityBase)
  1264.         CloseLibrary(UtilityBase);
  1265.  
  1266.     if(AslBase)
  1267.         CloseLibrary(AslBase);
  1268.  
  1269.     if(GadToolsBase)
  1270.         CloseLibrary(GadToolsBase);
  1271.  
  1272.     if(GfxBase)
  1273.         CloseLibrary(GfxBase);
  1274.  
  1275.     if(IntuitionBase)
  1276.         CloseLibrary(IntuitionBase);
  1277.  
  1278.     if(RendezvousData)
  1279.     {
  1280.         (*RendezvousSemaphore -> rs_Logoff)(RendezvousData);
  1281.  
  1282.         RendezvousData = NULL;
  1283.     }
  1284.  
  1285.     if(RendezvousSemaphore)
  1286.     {
  1287.         ReleaseSemaphore(RendezvousSemaphore);
  1288.  
  1289.         RendezvousSemaphore = NULL;
  1290.     }
  1291.  
  1292.     if(pri != 1000)
  1293.         OldPri = SetTaskPri(ThisProcess,OldPri);
  1294. }
  1295.  
  1296.     /* ConPutc():
  1297.      *
  1298.      *    Output a single character.
  1299.      */
  1300.  
  1301. VOID __stdargs
  1302. ConPutc(struct IOStdReq *Request,UBYTE Char)
  1303. {
  1304.     Request -> io_Command    = CMD_WRITE;
  1305.     Request -> io_Data    = &Char;
  1306.     Request -> io_Length    = 1;
  1307.  
  1308.     DoIO(Request);
  1309. }
  1310.  
  1311.     /* ConPuts():
  1312.      *
  1313.      *    Output a string.
  1314.      */
  1315.  
  1316. VOID
  1317. ConPuts(struct IOStdReq *Request,STRPTR String)
  1318. {
  1319.     Request -> io_Command    = CMD_WRITE;
  1320.     Request -> io_Data    = String;
  1321.     Request -> io_Length    = strlen(String);
  1322.  
  1323.     DoIO(Request);
  1324. }
  1325.  
  1326.     /* ConPrintf():
  1327.      *
  1328.      *    Formatted console output.
  1329.      */
  1330.  
  1331. VOID __stdargs
  1332. ConPrintf(struct IOStdReq *Request,STRPTR Format,...)
  1333. {
  1334.     STATIC UBYTE Buffer[512];
  1335.  
  1336.     va_list    VarArgs;
  1337.     LONG    Len;
  1338.  
  1339.     va_start(VarArgs,Format);
  1340.     vsprintf(Buffer,Format,VarArgs);
  1341.     va_end(VarArgs);
  1342.  
  1343.     Len = strlen(Buffer);
  1344.  
  1345.     if(Buffer[0] != '\033' && Request == FileRequest)
  1346.     {
  1347.         struct ConUnit *Unit = (struct ConUnit *)Request -> io_Unit;
  1348.  
  1349.         if(Unit -> cu_XCCP + Len > Unit -> cu_XMax)
  1350.         {
  1351.             if((Len = Unit -> cu_XMax - Unit -> cu_XCCP) < 1)
  1352.                 return;
  1353.         }
  1354.     }
  1355.  
  1356.     Request -> io_Command    = CMD_WRITE;
  1357.     Request -> io_Data    = Buffer;
  1358.     Request -> io_Length    = Len;
  1359.  
  1360.     DoIO(Request);
  1361. }
  1362.  
  1363.     /* ConMove():
  1364.      *
  1365.      *    Move the cursor to a new position.
  1366.      */
  1367.  
  1368. VOID
  1369. ConMove(struct IOStdReq *Request,LONG x,LONG y)
  1370. {
  1371.     ConPrintf(Request,"\33[%ld;%ldH",y,x);
  1372. }
  1373.  
  1374.     /* ConClear():
  1375.      *
  1376.      *    Clear the console window.
  1377.      */
  1378.  
  1379. VOID
  1380. ConClear(struct IOStdReq *Request)
  1381. {
  1382.     struct ConUnit *ConUnit = (struct ConUnit *)Request -> io_Device;
  1383.     LONG x,y;
  1384.  
  1385.     x = ConUnit -> cu_XCCP;
  1386.     y = ConUnit -> cu_YCCP;
  1387.  
  1388.     ConPrintf(Request,"\033[2J\33[%ld;%ldH",y,x);
  1389. }
  1390.  
  1391.     /* ConGetKey():
  1392.      *
  1393.      *    Read a character from a console window.
  1394.      */
  1395.  
  1396. int
  1397. ConGetKey()
  1398. {
  1399.     if(ConsoleReady)
  1400.     {
  1401.         int Result = ConsoleChar;
  1402.  
  1403.         ConsoleReady = FALSE;
  1404.  
  1405.         ConsoleReadRequest -> io_Command    = CMD_READ;
  1406.         ConsoleReadRequest -> io_Data        = &ConsoleChar;
  1407.         ConsoleReadRequest -> io_Length        = 1;
  1408.  
  1409.         ClrSignal(SIG_CONREAD);
  1410.         SendIO(ConsoleReadRequest);
  1411.  
  1412.         return(Result);
  1413.     }
  1414.     else
  1415.     {
  1416.         int Result = 0;
  1417.  
  1418.         if(WindowReady)
  1419.         {
  1420.             struct IntuiMessage *IntuiMessage;
  1421.             ULONG MsgClass;
  1422.             UWORD MsgCode;
  1423.  
  1424.             while(IntuiMessage = (struct IntuiMessage *)GetMsg(LocalWindow -> UserPort))
  1425.             {
  1426.                 MsgClass    = IntuiMessage -> Class;
  1427.                 MsgCode        = IntuiMessage -> Code;
  1428.  
  1429.                 ReplyMsg(IntuiMessage);
  1430.  
  1431.                 if(MsgClass == IDCMP_MENUPICK)
  1432.                 {
  1433.                     struct MenuItem *Item;
  1434.  
  1435.                     while(MsgCode != MENUNULL)
  1436.                     {
  1437.                         if(Item = ItemAddress(Menu,MsgCode))
  1438.                         {
  1439.                             if(MENU_USERDATA(Item))
  1440.                             {
  1441.                                 if(!Result)
  1442.                                     Result = (int)MENU_USERDATA(Item);
  1443.                             }
  1444.  
  1445.                             MsgCode = Item -> NextSelect;
  1446.                         }
  1447.                         else
  1448.                             break;
  1449.                     }
  1450.                 }
  1451.             }
  1452.  
  1453.             WindowReady = FALSE;
  1454.         }
  1455.  
  1456.         return(Result);
  1457.     }
  1458. }
  1459.  
  1460.     /* ConScanKey():
  1461.      *
  1462.      *    Check for a keyboard event.
  1463.      */
  1464.  
  1465. int
  1466. ConScanKey()
  1467. {
  1468.     if(ConsoleReady || WindowReady)
  1469.         return(1);
  1470.     else
  1471.     {
  1472.         int Result = 0;
  1473.  
  1474.         if(CheckSignal(SIG_WINDOW))
  1475.         {
  1476.             WindowReady = TRUE;
  1477.  
  1478.             Result = 1;
  1479.         }
  1480.  
  1481.         if(CheckIO(ConsoleReadRequest))
  1482.         {
  1483.             if(!WaitIO(ConsoleReadRequest))
  1484.             {
  1485.                 ConsoleReady = TRUE;
  1486.  
  1487.                 return(1);
  1488.             }
  1489.             else
  1490.             {
  1491.                 ConsoleReadRequest -> io_Command    = CMD_READ;
  1492.                 ConsoleReadRequest -> io_Data        = &ConsoleChar;
  1493.                 ConsoleReadRequest -> io_Length        = 1;
  1494.  
  1495.                 ClrSignal(SIG_CONREAD);
  1496.                 SendIO(ConsoleReadRequest);
  1497.             }
  1498.         }
  1499.  
  1500.         return(Result);
  1501.     }
  1502.  
  1503.     return(0);
  1504. }
  1505.  
  1506.     /* dtr_out(byte flag):
  1507.      *
  1508.      *    If flag == 0 -> drop DTR signal, else set it.
  1509.      */
  1510.  
  1511. VOID
  1512. dtr_out(byte flag)
  1513. {
  1514.     if(!flag && !RendezvousData)
  1515.     {
  1516.         if(ThisBuffer -> IsBusy)
  1517.         {
  1518.             WaitIO(ThisBuffer -> SerialRequest);
  1519.  
  1520.             ThisBuffer -> IsBusy        = FALSE;
  1521.             ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1522.         }
  1523.  
  1524.         if(ReadBuffer -> IsBusy)
  1525.         {
  1526.             if(!CheckIO(ReadBuffer -> SerialRequest))
  1527.                 AbortIO(ReadBuffer -> SerialRequest);
  1528.  
  1529.             WaitIO(ReadBuffer -> SerialRequest);
  1530.  
  1531.             ReadBuffer -> IsBusy        = FALSE;
  1532.             ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1533.             ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1534.  
  1535.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1536.  
  1537.             DoIO(ReadBuffer -> SerialRequest);
  1538.  
  1539.             if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1540.             {
  1541.                 LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1542.  
  1543.                 if(Size > 0)
  1544.                 {
  1545.                     if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1546.                         Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1547.  
  1548.                     ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1549.                     ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1550.                     ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1551.  
  1552.                     DoIO(ReadBuffer -> SerialRequest);
  1553.  
  1554.                     ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1555.                 }
  1556.             }
  1557.         }
  1558.  
  1559.         CloseDevice(ReadBuffer -> SerialRequest);
  1560.  
  1561.         TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  1562.         TimeRequest -> tr_time . tv_secs    = 1;
  1563.         TimeRequest -> tr_time . tv_micro    = 0;
  1564.  
  1565.         DoIO(TimeRequest);
  1566.  
  1567.         if(OpenDevice(device,port,ReadBuffer -> SerialRequest,NULL))
  1568.         {
  1569.             CloseAll();
  1570.  
  1571.             exit(10);
  1572.         }
  1573.         else
  1574.         {
  1575.             ReadBuffer -> SerialRequest -> io_Baud        = ThisBuffer -> SerialRequest -> io_Baud;
  1576.             ReadBuffer -> SerialRequest -> io_ReadLen    = ThisBuffer -> SerialRequest -> io_ReadLen;
  1577.             ReadBuffer -> SerialRequest -> io_WriteLen    = ThisBuffer -> SerialRequest -> io_WriteLen;
  1578.             ReadBuffer -> SerialRequest -> io_SerFlags    = ThisBuffer -> SerialRequest -> io_SerFlags;
  1579.  
  1580.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_SETPARAMS;
  1581.  
  1582.             DoIO(ReadBuffer -> SerialRequest);
  1583.  
  1584.             CopyMem(ReadBuffer -> SerialRequest,ThisBuffer -> SerialRequest,sizeof(struct IOExtSer));
  1585.  
  1586.             ThisBuffer -> SerialRequest -> IOSer . io_Message . mn_ReplyPort = WritePort;
  1587.  
  1588.             CopyMem(ReadBuffer -> SerialRequest,NextBuffer -> SerialRequest,sizeof(struct IOExtSer));
  1589.  
  1590.             NextBuffer -> SerialRequest -> IOSer . io_Message . mn_ReplyPort = WritePort;
  1591.         }
  1592.     }
  1593. }
  1594.  
  1595.     /* com_flow(byte flags):
  1596.      *
  1597.      *    The bit mask `flags' determines the style(s) of
  1598.      *    handshaking:
  1599.      *
  1600.      *    if (flags & 9) -> enable xON/xOFF software handshaking,
  1601.      *    if (flags & 2) -> enable RTS/CTS hardware handshaking
  1602.      */
  1603.  
  1604. VOID
  1605. com_flow(byte flags)
  1606. {
  1607.     if(ThisBuffer -> IsBusy)
  1608.     {
  1609.         WaitIO(ThisBuffer -> SerialRequest);
  1610.  
  1611.         ThisBuffer -> IsBusy        = FALSE;
  1612.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1613.     }
  1614.  
  1615.     if(ReadBuffer -> IsBusy)
  1616.     {
  1617.         if(!CheckIO(ReadBuffer -> SerialRequest))
  1618.             AbortIO(ReadBuffer -> SerialRequest);
  1619.  
  1620.         WaitIO(ReadBuffer -> SerialRequest);
  1621.  
  1622.         ReadBuffer -> IsBusy        = FALSE;
  1623.         ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1624.         ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1625.  
  1626.         ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1627.  
  1628.         DoIO(ReadBuffer -> SerialRequest);
  1629.  
  1630.         if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1631.         {
  1632.             LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1633.  
  1634.             if(Size > 0)
  1635.             {
  1636.                 if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1637.                     Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1638.  
  1639.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1640.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1641.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1642.  
  1643.                 DoIO(ReadBuffer -> SerialRequest);
  1644.  
  1645.                 ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1646.             }
  1647.         }
  1648.     }
  1649.  
  1650.     if(flags & 2)
  1651.         ReadBuffer -> SerialRequest -> io_SerFlags |= SERF_7WIRE;
  1652.     else
  1653.         ReadBuffer -> SerialRequest -> io_SerFlags &= ~SERF_7WIRE;
  1654.  
  1655.     if(flags & 9)
  1656.         ReadBuffer -> SerialRequest -> io_SerFlags &= ~SERF_XDISABLED;
  1657.     else
  1658.         ReadBuffer -> SerialRequest -> io_SerFlags |= SERF_XDISABLED;
  1659.  
  1660.     ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_SETPARAMS;
  1661.  
  1662.     DoIO(ReadBuffer -> SerialRequest);
  1663.  
  1664.     ThisBuffer -> SerialRequest -> io_SerFlags = ReadBuffer -> SerialRequest -> io_SerFlags;
  1665.     NextBuffer -> SerialRequest -> io_SerFlags = ReadBuffer -> SerialRequest -> io_SerFlags;
  1666. }
  1667.  
  1668.     /* com_setspeed(word speed):
  1669.      *
  1670.      *    Set the transfer speed (in bits/second).
  1671.      */
  1672.  
  1673. VOID
  1674. com_setspeed(word speed)
  1675. {
  1676.     if(ThisBuffer -> IsBusy)
  1677.     {
  1678.         WaitIO(ThisBuffer -> SerialRequest);
  1679.  
  1680.         ThisBuffer -> IsBusy        = FALSE;
  1681.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1682.     }
  1683.  
  1684.     if(ReadBuffer -> IsBusy)
  1685.     {
  1686.         if(!CheckIO(ReadBuffer -> SerialRequest))
  1687.             AbortIO(ReadBuffer -> SerialRequest);
  1688.  
  1689.         WaitIO(ReadBuffer -> SerialRequest);
  1690.  
  1691.         ReadBuffer -> IsBusy        = FALSE;
  1692.         ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1693.         ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1694.  
  1695.         ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1696.  
  1697.         DoIO(ReadBuffer -> SerialRequest);
  1698.  
  1699.         if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1700.         {
  1701.             LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1702.  
  1703.             if(Size > 0)
  1704.             {
  1705.                 if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1706.                     Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1707.  
  1708.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1709.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1710.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1711.  
  1712.                 DoIO(ReadBuffer -> SerialRequest);
  1713.  
  1714.                 ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1715.             }
  1716.         }
  1717.     }
  1718.  
  1719.     ReadBuffer -> SerialRequest -> io_Baud = speed;
  1720.  
  1721.     if(parity)
  1722.     {
  1723.         ReadBuffer -> SerialRequest -> io_ReadLen = ReadBuffer -> SerialRequest -> io_WriteLen = 7;
  1724.         ReadBuffer -> SerialRequest -> io_SerFlags |= SERF_PARTY_ON;
  1725.     }
  1726.     else
  1727.     {
  1728.         ReadBuffer -> SerialRequest -> io_ReadLen = ReadBuffer -> SerialRequest -> io_WriteLen = 8;
  1729.         ReadBuffer -> SerialRequest -> io_SerFlags &= ~SERF_PARTY_ON;
  1730.     }
  1731.  
  1732.     ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_SETPARAMS;
  1733.  
  1734.     DoIO(ReadBuffer -> SerialRequest);
  1735.  
  1736.     ThisBuffer -> SerialRequest -> io_Baud        = ReadBuffer -> SerialRequest -> io_Baud;
  1737.     ThisBuffer -> SerialRequest -> io_ReadLen    = ReadBuffer -> SerialRequest -> io_ReadLen;
  1738.     ThisBuffer -> SerialRequest -> io_WriteLen    = ReadBuffer -> SerialRequest -> io_WriteLen;
  1739.     ThisBuffer -> SerialRequest -> io_SerFlags    = ReadBuffer -> SerialRequest -> io_SerFlags;
  1740.  
  1741.     NextBuffer -> SerialRequest -> io_Baud        = ReadBuffer -> SerialRequest -> io_Baud;
  1742.     NextBuffer -> SerialRequest -> io_ReadLen    = ReadBuffer -> SerialRequest -> io_ReadLen;
  1743.     NextBuffer -> SerialRequest -> io_WriteLen    = ReadBuffer -> SerialRequest -> io_WriteLen;
  1744.     NextBuffer -> SerialRequest -> io_SerFlags    = ReadBuffer -> SerialRequest -> io_SerFlags;
  1745. }
  1746.  
  1747.     /* com_putblock(byte *s,word len):
  1748.      *
  1749.      *    Send a data block asynchronously.
  1750.      */
  1751.  
  1752. VOID
  1753. com_putblock(byte *s,word len)
  1754. {
  1755.     struct SerialBuffer *Swap = ThisBuffer;
  1756.  
  1757.     if(ThisBuffer -> IsBusy)
  1758.         WaitIO(ThisBuffer -> SerialRequest);
  1759.     else
  1760.     {
  1761.         if(ThisBuffer -> SerialIndex > ThisBuffer -> SerialBuffer)
  1762.         {
  1763.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1764.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1765.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  1766.  
  1767.             DoIO(ThisBuffer -> SerialRequest);
  1768.         }
  1769.     }
  1770.  
  1771.     ThisBuffer -> IsBusy        = FALSE;
  1772.     ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1773.  
  1774.     ThisBuffer = NextBuffer;
  1775.     NextBuffer = Swap;
  1776.  
  1777.     if(ThisBuffer -> SerialIndex > ThisBuffer -> SerialBuffer)
  1778.     {
  1779.         ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1780.         ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1781.         ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  1782.  
  1783.         DoIO(ThisBuffer -> SerialRequest);
  1784.     }
  1785.  
  1786.     ThisBuffer -> IsBusy        = FALSE;
  1787.     ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1788.  
  1789.     while(len > 2 * ThisBuffer -> SerialSize)
  1790.     {
  1791.         ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1792.         ThisBuffer -> SerialRequest -> IOSer . io_Data        = s;
  1793.         ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialSize;
  1794.  
  1795.         s    += ThisBuffer -> SerialSize;
  1796.         len    -= ThisBuffer -> SerialSize;
  1797.  
  1798.         DoIO(ThisBuffer -> SerialRequest);
  1799.     }
  1800.  
  1801.     CopyMem(s,ThisBuffer -> SerialBuffer,MIN(len,ThisBuffer -> SerialSize));
  1802.  
  1803.     ThisBuffer -> IsBusy                    = TRUE;
  1804.     ThisBuffer -> SerialIndex                = ThisBuffer -> SerialBuffer + MIN(len,ThisBuffer -> SerialSize);
  1805.     ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1806.     ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1807.     ThisBuffer -> SerialRequest -> IOSer . io_Length    = MIN(len,ThisBuffer -> SerialSize);
  1808.  
  1809.     len    -= ThisBuffer -> SerialRequest -> IOSer . io_Length;
  1810.     s    += ThisBuffer -> SerialRequest -> IOSer . io_Length;
  1811.  
  1812.     ClrSignal(SIG_SERWRITE);
  1813.     SendIO(ThisBuffer -> SerialRequest);
  1814.  
  1815.     if(len > 0)
  1816.     {
  1817.         CopyMem(s,NextBuffer -> SerialBuffer,len);
  1818.  
  1819.         NextBuffer -> SerialIndex = NextBuffer -> SerialBuffer + len;
  1820.     }
  1821. }
  1822.  
  1823.     /* breakfunc():
  1824.      *
  1825.      *    Cleanup routine for SAS/C.
  1826.      */
  1827.  
  1828. static int
  1829. breakfunc(void)
  1830. {
  1831.     CloseAll();
  1832.  
  1833.     return(1);
  1834. }
  1835.  
  1836.     /* sys_init(VOID):
  1837.      *
  1838.      *    Initialize this driver implementation.
  1839.      */
  1840.  
  1841. VOID
  1842. sys_init(VOID)
  1843. {
  1844.     if(!OpenAll(device,port))
  1845.     {
  1846.         CloseAll();
  1847.  
  1848.         endprog(2);
  1849.     }
  1850.  
  1851.     onbreak(breakfunc);
  1852. }
  1853.  
  1854.     /* sys_reset(VOID):
  1855.      *
  1856.      *    Perform cleanup for this driver implementation.
  1857.      */
  1858.  
  1859. VOID
  1860. sys_reset(VOID)
  1861. {
  1862.     CloseAll();
  1863. }
  1864.  
  1865.     /* sys_idle(VOID):
  1866.      *
  1867.      *    This routine gets called when the system is idle.
  1868.      *    That's a nice one. We are supposed to call the
  1869.      *    system scheduler, etc.
  1870.      */
  1871.  
  1872. VOID
  1873. sys_idle(VOID)
  1874. {
  1875.     ULONG Signals;
  1876.  
  1877.     if(ReadBuffer -> SerialFilled <= 0 && !ReadBuffer -> IsBusy)
  1878.     {
  1879.         ReadBuffer -> IsBusy                    = TRUE;
  1880.         ReadBuffer -> SerialIndex                = ReadBuffer -> SerialBuffer;
  1881.         ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1882.         ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer;
  1883.         ReadBuffer -> SerialRequest -> IOSer . io_Length    = 1;
  1884.  
  1885.         ClrSignal(SIG_SERREAD);
  1886.         SendIO(ReadBuffer -> SerialRequest);
  1887.     }
  1888.  
  1889.     TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  1890.     TimeRequest -> tr_time . tv_secs    = 1;
  1891.     TimeRequest -> tr_time . tv_micro    = 0;
  1892.  
  1893.     ClrSignal(SIG_TIMER);
  1894.     SendIO(TimeRequest);
  1895.  
  1896.     Signals = Wait(SIG_SERREAD | SIG_SERWRITE | SIG_CONREAD | SIG_WINDOW | SIG_TIMER);
  1897.  
  1898.     if(!(Signals & SIG_TIMER))
  1899.     {
  1900.         if(!CheckIO(TimeRequest))
  1901.             AbortIO(TimeRequest);
  1902.     }
  1903.  
  1904.     WaitIO(TimeRequest);
  1905.  
  1906.     if(Signals & SIG_SERREAD)
  1907.     {
  1908.         WaitIO(ReadBuffer -> SerialRequest);
  1909.  
  1910.         ReadBuffer -> IsBusy        = FALSE;
  1911.         ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1912.         ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1913.  
  1914.         ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1915.  
  1916.         DoIO(ReadBuffer -> SerialRequest);
  1917.  
  1918.         if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1919.         {
  1920.             LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1921.  
  1922.             if(Size > 0)
  1923.             {
  1924.                 if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1925.                     Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1926.  
  1927.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1928.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1929.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1930.  
  1931.                 DoIO(ReadBuffer -> SerialRequest);
  1932.  
  1933.                 ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1934.             }
  1935.         }
  1936.     }
  1937.  
  1938.     if(Signals & SIG_SERWRITE)
  1939.     {
  1940.         struct SerialBuffer *Swap = ThisBuffer;
  1941.  
  1942.         WaitIO(ThisBuffer -> SerialRequest);
  1943.  
  1944.         ThisBuffer -> IsBusy        = FALSE;
  1945.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1946.  
  1947.         ThisBuffer = NextBuffer;
  1948.         NextBuffer = Swap;
  1949.     }
  1950.  
  1951.     if(Signals & SIG_CONREAD)
  1952.     {
  1953.         WaitIO(ConsoleReadRequest);
  1954.  
  1955.         ConsoleReady = TRUE;
  1956.     }
  1957.  
  1958.     if(Signals & SIG_WINDOW)
  1959.         WindowReady = TRUE;
  1960. }
  1961.  
  1962.     /* com_outfull(VOID):
  1963.      *
  1964.      *    Return number of bytes still to be transferred.
  1965.      */
  1966.  
  1967. int
  1968. com_outfull(VOID)
  1969. {
  1970.     return(ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer + NextBuffer -> SerialIndex - NextBuffer -> SerialBuffer);
  1971. }
  1972.  
  1973.     /* carrier(VOID):
  1974.      *
  1975.      *    Return current carrier status.
  1976.      */
  1977.  
  1978. int
  1979. carrier(VOID)
  1980. {
  1981.     if(nocarrier)
  1982.         return(1);
  1983.     else
  1984.     {
  1985.         if(!ThisBuffer -> IsBusy)
  1986.         {
  1987.             ThisBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1988.  
  1989.             DoIO(ThisBuffer -> SerialRequest);
  1990.  
  1991.             if(ThisBuffer -> SerialRequest -> io_Status & CIAF_COMCD)
  1992.                 return(0);
  1993.             else
  1994.                 return(1);
  1995.         }
  1996.         else
  1997.         {
  1998.             NextBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1999.  
  2000.             DoIO(NextBuffer -> SerialRequest);
  2001.  
  2002.             if(NextBuffer -> SerialRequest -> io_Status & CIAF_COMCD)
  2003.                 return(0);
  2004.             else
  2005.                 return(1);
  2006.         }
  2007.     }
  2008. }
  2009.  
  2010.     /* com_flush(VOID):
  2011.      *
  2012.      *    Make sure all pending data gets written.
  2013.      */
  2014.  
  2015. VOID
  2016. com_flush(VOID)
  2017. {
  2018.     if(ThisBuffer -> IsBusy)
  2019.     {
  2020.         WaitIO(ThisBuffer -> SerialRequest);
  2021.  
  2022.         ThisBuffer -> IsBusy        = FALSE;
  2023.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  2024.     }
  2025.  
  2026.     if(NextBuffer -> SerialIndex > NextBuffer -> SerialBuffer)
  2027.     {
  2028.         NextBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  2029.         NextBuffer -> SerialRequest -> IOSer . io_Data        = NextBuffer -> SerialBuffer;
  2030.         NextBuffer -> SerialRequest -> IOSer . io_Length    = NextBuffer -> SerialIndex - NextBuffer -> SerialBuffer;
  2031.  
  2032.         DoIO(NextBuffer -> SerialRequest);
  2033.  
  2034.         NextBuffer -> SerialIndex = NextBuffer -> SerialBuffer;
  2035.     }
  2036. }
  2037.  
  2038.     /* com_putbyte(byte c):
  2039.      *
  2040.      *    Transmit a single byte, queueing it if necessary.
  2041.      */
  2042.  
  2043. VOID
  2044. com_putbyte(byte c)
  2045. {
  2046.     if(ThisBuffer -> IsBusy)
  2047.     {
  2048.         if(NextBuffer -> SerialIndex + 1 >= NextBuffer -> SerialTop)
  2049.         {
  2050.             struct SerialBuffer *Swap = ThisBuffer;
  2051.  
  2052.             WaitIO(ThisBuffer -> SerialRequest);
  2053.  
  2054.             ThisBuffer -> IsBusy        = FALSE;
  2055.             ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  2056.  
  2057.             ThisBuffer = NextBuffer;
  2058.             NextBuffer = Swap;
  2059.  
  2060.             ThisBuffer -> IsBusy                    = TRUE;
  2061.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  2062.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  2063.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  2064.  
  2065.             ClrSignal(SIG_SERWRITE);
  2066.             SendIO(ThisBuffer -> SerialRequest);
  2067.         }
  2068.  
  2069.         *NextBuffer -> SerialIndex++ = c;
  2070.     }
  2071.     else
  2072.     {
  2073.         if(ThisBuffer -> SerialIndex + 1 < ThisBuffer -> SerialTop)
  2074.         {
  2075.             *ThisBuffer -> SerialIndex++ = c;
  2076.  
  2077.             ThisBuffer -> IsBusy                    = TRUE;
  2078.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  2079.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  2080.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = 1;
  2081.  
  2082.             ClrSignal(SIG_SERWRITE);
  2083.             SendIO(ThisBuffer -> SerialRequest);
  2084.         }
  2085.         else
  2086.         {
  2087.             ThisBuffer -> IsBusy                    = TRUE;
  2088.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  2089.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  2090.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  2091.  
  2092.             ClrSignal(SIG_SERWRITE);
  2093.             SendIO(ThisBuffer -> SerialRequest);
  2094.  
  2095.             *NextBuffer -> SerialIndex++ = c;
  2096.         }
  2097.     }
  2098. }
  2099.  
  2100.     /* com_purge(VOID):
  2101.      *
  2102.      *    Clear the read/write buffers.
  2103.      */
  2104.  
  2105. VOID
  2106. com_purge(VOID)
  2107. {
  2108.     if(ThisBuffer -> IsBusy)
  2109.     {
  2110.         if(!CheckIO(ThisBuffer -> SerialRequest))
  2111.             AbortIO(ThisBuffer -> SerialRequest);
  2112.  
  2113.         WaitIO(ThisBuffer -> SerialRequest);
  2114.     }
  2115.  
  2116.     ThisBuffer -> IsBusy        = FALSE;
  2117.     ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  2118.  
  2119.     NextBuffer -> IsBusy        = FALSE;
  2120.     NextBuffer -> SerialIndex    = NextBuffer -> SerialBuffer;
  2121.  
  2122.     if(ReadBuffer -> IsBusy)
  2123.     {
  2124.         if(!CheckIO(ReadBuffer -> SerialRequest))
  2125.             AbortIO(ReadBuffer -> SerialRequest);
  2126.  
  2127.         WaitIO(ReadBuffer -> SerialRequest);
  2128.     }
  2129.  
  2130.     ReadBuffer -> IsBusy        = FALSE;
  2131.     ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  2132.     ReadBuffer -> SerialFilled    = 0;
  2133.  
  2134.     ThisBuffer -> SerialRequest -> IOSer . io_Command = CMD_CLEAR;
  2135.     DoIO(ThisBuffer -> SerialRequest);
  2136. }
  2137.  
  2138.     /* com_dump(VOID):
  2139.      *
  2140.      *    Wait for asynchronous write request to terminate.
  2141.      */
  2142.  
  2143. VOID
  2144. com_dump(VOID)
  2145. {
  2146.     com_flush();
  2147. }
  2148.  
  2149.     /* com_getbyte(VOID):
  2150.      *
  2151.      *    Read a single byte from the serial line. If not available,
  2152.      *    return EOF.
  2153.      */
  2154.  
  2155. int
  2156. com_getbyte(VOID)
  2157. {
  2158.     int Result;
  2159.  
  2160.     if(ReadBuffer -> SerialFilled <= 0)
  2161.     {
  2162.         if(ReadBuffer -> IsBusy)
  2163.         {
  2164.             if(!CheckIO(ReadBuffer -> SerialRequest))
  2165.                 return(EOF);
  2166.             else
  2167.                 WaitIO(ReadBuffer -> SerialRequest);
  2168.  
  2169.             ReadBuffer -> IsBusy        = FALSE;
  2170.             ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  2171.             ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  2172.  
  2173.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  2174.  
  2175.             DoIO(ReadBuffer -> SerialRequest);
  2176.  
  2177.             if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  2178.             {
  2179.                 LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  2180.  
  2181.                 if(Size > 0)
  2182.                 {
  2183.                     if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  2184.                         Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  2185.  
  2186.                     ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  2187.                     ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  2188.                     ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  2189.  
  2190.                     DoIO(ReadBuffer -> SerialRequest);
  2191.  
  2192.                     ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  2193.                 }
  2194.             }
  2195.         }
  2196.         else
  2197.         {
  2198.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  2199.  
  2200.             DoIO(ReadBuffer -> SerialRequest);
  2201.  
  2202.             if(!ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  2203.                 return(EOF);
  2204.             else
  2205.             {
  2206.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  2207.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer;
  2208.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = MIN(ReadBuffer -> SerialRequest -> IOSer . io_Actual,ReadBuffer -> SerialSize);
  2209.  
  2210.                 DoIO(ReadBuffer -> SerialRequest);
  2211.  
  2212.                 if(!ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  2213.                     return(EOF);
  2214.                 else
  2215.                 {
  2216.                     ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  2217.                     ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  2218.                 }
  2219.             }
  2220.         }
  2221.     }
  2222.  
  2223.     Result = *ReadBuffer -> SerialIndex++;
  2224.  
  2225.     ReadBuffer -> SerialFilled--;
  2226.  
  2227.     if(ReadBuffer -> SerialFilled <= 0)
  2228.     {
  2229.         ReadBuffer -> IsBusy                    = TRUE;
  2230.         ReadBuffer -> SerialIndex                = ReadBuffer -> SerialBuffer;
  2231.  
  2232.         ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  2233.         ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer;
  2234.         ReadBuffer -> SerialRequest -> IOSer . io_Length    = 1;
  2235.  
  2236.         ClrSignal(SIG_SERREAD);
  2237.         SendIO(ReadBuffer -> SerialRequest);
  2238.     }
  2239.  
  2240.     return(Result);
  2241. }
  2242.  
  2243.     /* setstamp(STRPTR Name,LONG Time):
  2244.      *
  2245.      *    Set time/date of a file.
  2246.      */
  2247.  
  2248. VOID
  2249. setstamp(char *Name,long Time)
  2250. {
  2251.     struct DateStamp    Date;
  2252.     ULONG            Seconds;
  2253.  
  2254.     DB(kprintf("setstamp |%s| %ld\n",Name,Time));
  2255.  
  2256.         /* Translate it into an Amiga date. */
  2257.  
  2258.     if(Time > GMT_Offset)
  2259.         Seconds = Time - GMT_Offset;
  2260.     else
  2261.         Seconds = 0;
  2262.  
  2263.     Date . ds_Days        = Seconds / (24 * 60 * 60);
  2264.     Date . ds_Minute    = (Seconds % (24 * 60 * 60)) / 60;
  2265.     Date . ds_Tick        = (Seconds % 60) * TICKS_PER_SECOND;
  2266.  
  2267.     SetFileDate(Name,&Date);
  2268. }
  2269.  
  2270.     /* freespace(STRPTR DrivePath):
  2271.      *
  2272.      *    Get free disk space for specified drive.
  2273.      */
  2274.  
  2275. long
  2276. freespace(char *DrivePath)
  2277. {
  2278.     struct DevProc    *DevProc;
  2279.     struct DosList    *DosList;
  2280.     BOOL         GoodDevice;
  2281.     LONG         Size;
  2282.  
  2283.     if(!DrivePath)
  2284.         DrivePath = "";
  2285.  
  2286.     DB(kprintf("freespace |%s|\n",DrivePath));
  2287.  
  2288.     DevProc = GetDeviceProc(DrivePath,NULL);
  2289.  
  2290.     GoodDevice = FALSE;
  2291.     Size = (LONG)((ULONG)~0 >> 2);
  2292.  
  2293.     if(DosList = LockDosList(LDF_DEVICES | LDF_READ))
  2294.     {
  2295.         while(DosList = NextDosEntry(DosList,LDF_DEVICES))
  2296.         {
  2297.             if(DosList -> dol_Task == DevProc -> dvp_Port)
  2298.             {
  2299.                 struct FileSysStartupMsg *FSSM = (struct FileSysStartupMsg *)BADDR(DosList -> dol_misc . dol_handler . dol_Startup);
  2300.  
  2301.                 if(TypeOfMem(FSSM))
  2302.                 {
  2303.                     struct DosEnvec *DosEnvec = (struct DosEnvec *)BADDR(FSSM -> fssm_Environ);
  2304.                     STRPTR Name = (STRPTR)BADDR(FSSM -> fssm_Device);
  2305.  
  2306.                     if(TypeOfMem(DosEnvec) && TypeOfMem(Name))
  2307.                     {
  2308.                         if(Name[0] > 0 && !Name[(WORD)Name[0] + 1])
  2309.                         {
  2310.                             struct IOStdReq __aligned IORequest;
  2311.  
  2312.                             if(!OpenDevice(Name + 1,FSSM -> fssm_Unit,&IORequest,FSSM -> fssm_Unit))
  2313.                             {
  2314.                                 CloseDevice(&IORequest);
  2315.  
  2316.                                 if(DosEnvec -> de_TableSize > 0 && DosEnvec -> de_LowCyl <= DosEnvec -> de_HighCyl)
  2317.                                     GoodDevice = TRUE;
  2318.                             }
  2319.                         }
  2320.                     }
  2321.                 }
  2322.             }
  2323.         }
  2324.  
  2325.         UnLockDosList(LDF_DEVICES | LDF_READ);
  2326.     }
  2327.  
  2328.     FreeDeviceProc(DevProc);
  2329.  
  2330.     if(GoodDevice)
  2331.     {
  2332.         struct InfoData *InfoData;
  2333.  
  2334.         if(InfoData = (struct InfoData *)AllocVec(sizeof(struct InfoData),MEMF_ANY | MEMF_PUBLIC))
  2335.         {
  2336.             UBYTE NewName[256],*Index;
  2337.             BPTR FileLock;
  2338.  
  2339.             memcpy(NewName,DrivePath,255);
  2340.  
  2341.             NewName[255] = 0;
  2342.  
  2343.             Index = PathPart(NewName);
  2344.  
  2345.             *Index = 0;
  2346.  
  2347.             FileLock = Lock(NewName,ACCESS_READ);
  2348.  
  2349.             if(FileLock)
  2350.             {
  2351.                 if(Info(FileLock,InfoData))
  2352.                     Size = InfoData -> id_BytesPerBlock * (InfoData -> id_NumBlocks - InfoData -> id_NumBlocksUsed);
  2353.  
  2354.                 UnLock(FileLock);
  2355.             }
  2356.  
  2357.             FreeVec(InfoData);
  2358.         }
  2359.     }
  2360.  
  2361.     return(Size);
  2362. }
  2363.  
  2364.     /* ffirst(char *FileSpec):
  2365.      *
  2366.      *    Return name of first file matching the given specs.
  2367.      */
  2368.  
  2369. char *
  2370. ffirst(char *filespec)
  2371. {
  2372.     AnchorUsed = TRUE;
  2373.  
  2374.     DB(kprintf("ffirst |%s|\n",filespec));
  2375.  
  2376.     if(MatchFirst(filespec,Anchor))
  2377.         return(NULL);
  2378.     else
  2379.         return((char *)Anchor -> ap_Buf);
  2380. }
  2381.  
  2382.     /* fnext(VOID):
  2383.      *
  2384.      *    Return name of next file matching the given specs.
  2385.      */
  2386.  
  2387. char *
  2388. fnext(VOID)
  2389. {
  2390.     AnchorUsed = TRUE;
  2391.  
  2392.     DB(kprintf("fnext\n"));
  2393.  
  2394.     if(MatchNext(Anchor))
  2395.         return(NULL);
  2396.     else
  2397.         return((char *)Anchor -> ap_Buf);
  2398. }
  2399.  
  2400.     /* time(time_t *timeptr):
  2401.      *
  2402.      *    Get the current time.
  2403.      */
  2404.  
  2405. time_t
  2406. time(time_t *timeptr)
  2407. {
  2408.     struct timeval    Now;
  2409.     time_t        CurrentTime;
  2410.  
  2411.     DB(kprintf("time 0x%08lx\n",timeptr));
  2412.  
  2413.         /* If the timer is already available,
  2414.          * just read the time. Otherwise, open what
  2415.          * we need to tell the time.
  2416.          */
  2417.  
  2418.     if(TimerBase)
  2419.         GetSysTime(&Now);
  2420.     else
  2421.         UpdateTime(&Now);
  2422.  
  2423.         /* Determine the current time, taking the time
  2424.          * zone into account.
  2425.          */
  2426.  
  2427.     CurrentTime = (time_t)(Now . tv_secs + GMT_Offset);
  2428.  
  2429.     if(timeptr)
  2430.         *timeptr = CurrentTime;
  2431.  
  2432.     return(CurrentTime);
  2433. }
  2434.  
  2435.     /* localtime(const time_t *t):
  2436.      *
  2437.      *    Convert UTC into local time.
  2438.      */
  2439.  
  2440. struct tm *
  2441. localtime(const time_t *t)
  2442. {
  2443.     STATIC struct tm Time;
  2444.  
  2445.     ULONG            Seconds,
  2446.                 Delta;
  2447.     struct ClockData    ClockData;
  2448.     BOOL            CloseIt = FALSE;
  2449.  
  2450.     DB(kprintf("localtime 0x%08lx\n",t));
  2451.  
  2452.         /* We need utility.library for the date conversion. */
  2453.  
  2454.     if(!UtilityBase)
  2455.     {
  2456.         if(UtilityBase = OpenLibrary("utility.library",37))
  2457.             CloseIt = TRUE;
  2458.     }
  2459.  
  2460.         /* Any luck? */
  2461.  
  2462.     if(!UtilityBase)
  2463.     {
  2464.         memset(&Time,0,sizeof(struct tm));
  2465.  
  2466.         return(&Time);
  2467.     }
  2468.  
  2469.         /* Update the time data. */
  2470.  
  2471.     if(!TimerBase)
  2472.         UpdateTime(NULL);
  2473.  
  2474.         /* Add the offset. */
  2475.  
  2476.     if(*t < GMT_Offset)
  2477.         Seconds = 0;
  2478.     else
  2479.         Seconds = (ULONG)*t - GMT_Offset;
  2480.  
  2481.         /* Convert the seconds into time data. */
  2482.  
  2483.     Amiga2Date(Seconds,&ClockData);
  2484.  
  2485.         /* Convert the time data. */
  2486.  
  2487.     Time . tm_sec    = ClockData . sec;
  2488.     Time . tm_min    = ClockData . min;
  2489.     Time . tm_hour    = ClockData . hour;
  2490.     Time . tm_mday    = ClockData . mday;
  2491.     Time . tm_mon    = ClockData . month - 1;
  2492.     Time . tm_year    = ClockData . year - 1900;
  2493.     Time . tm_wday    = ClockData . wday;
  2494.  
  2495.         /* No daylight savings time info is provided. */
  2496.  
  2497.     Time . tm_isdst = 0;
  2498.  
  2499.         /* We will need to fill in the yday entry. */
  2500.  
  2501.     ClockData . mday    = 1;
  2502.     ClockData . month    = 1;
  2503.  
  2504.     Delta = Date2Amiga(&ClockData);
  2505.  
  2506.     Time . tm_yday = (Seconds - Delta) / (24 * 60 * 60) + 1;
  2507.  
  2508.         /* Clean up if necessary. */
  2509.  
  2510.     if(CloseIt)
  2511.     {
  2512.         CloseLibrary(UtilityBase);
  2513.  
  2514.         UtilityBase = NULL;
  2515.     }
  2516.  
  2517.     return(&Time);
  2518. }
  2519.  
  2520.     /* stat(const char *file,struct stat *st):
  2521.      *
  2522.      *    Get information on a file.
  2523.      */
  2524.  
  2525. int
  2526. stat(const char *file,struct stat *st)
  2527. {
  2528.     BPTR FileLock;
  2529.  
  2530.     DB(kprintf("stat |%s| 0%08lx\n",file,st));
  2531.  
  2532.         /* Try to get a lock on the file. */
  2533.  
  2534.     if(FileLock = Lock((STRPTR)file,ACCESS_READ))
  2535.     {
  2536.         STATIC char    Volume[256],
  2537.                 Comment[80];
  2538.  
  2539.         struct FileInfoBlock __aligned    FileInfo;
  2540.         struct InfoData __aligned    InfoData;
  2541.  
  2542.             /* Get information on file and filing system. */
  2543.  
  2544.         if(Examine(FileLock,&FileInfo) && Info(FileLock,&InfoData))
  2545.         {
  2546.             unsigned short mode = 0;
  2547.  
  2548.                 /* Try to get the name of the volume. */
  2549.  
  2550.             if(!NameFromLock(FileLock,Volume,256))
  2551.                 Volume[0] = 0;
  2552.             else
  2553.             {
  2554.                 WORD i;
  2555.  
  2556.                     /* Chop off everything after the colon. */
  2557.  
  2558.                 for(i = 0 ; i < 256 ; i++)
  2559.                 {
  2560.                     if(Volume[i] == ':')
  2561.                     {
  2562.                         Volume[i + 1] = 0;
  2563.  
  2564.                         break;
  2565.                     }
  2566.                 }
  2567.             }
  2568.  
  2569.             UnLock(FileLock);
  2570.  
  2571.                 /* Build the protection bits. */
  2572.  
  2573.             if(!(FileInfo . fib_Protection & FIBF_EXECUTE))
  2574.                 mode |= S_IEXECUTE;
  2575.  
  2576.             if(!(FileInfo . fib_Protection & FIBF_DELETE))
  2577.                 mode |= S_IDELETE;
  2578.  
  2579.             if(!(FileInfo . fib_Protection & FIBF_READ))
  2580.                 mode |= S_IREAD;
  2581.  
  2582.             if(!(FileInfo . fib_Protection & FIBF_WRITE))
  2583.                 mode |= S_IWRITE;
  2584.  
  2585.             if(!(FileInfo . fib_Protection & FIBF_ARCHIVE))
  2586.                 mode |= S_IARCHIVE;
  2587.  
  2588.             if(FileInfo . fib_Protection & FIBF_PURE)
  2589.                 mode |= S_IPURE;
  2590.  
  2591.             if(FileInfo . fib_Protection & FIBF_SCRIPT)
  2592.                 mode |= S_ISCRIPT;
  2593.  
  2594.                 /* Keep the comment. */
  2595.  
  2596.             strcpy(Comment,FileInfo . fib_Comment);
  2597.  
  2598.                 /* Fix the time if necessary. */
  2599.  
  2600.             if(!TimerBase)
  2601.                 UpdateTime(NULL);
  2602.  
  2603.                 /* Fill in the data. */
  2604.  
  2605.             st -> st_mode    = mode;
  2606.             st -> st_ino    = FileInfo . fib_DiskKey;
  2607.             st -> st_dev    = InfoData . id_DiskType;
  2608.             st -> st_rdev    = Volume;
  2609.             st -> st_nlink    = FileInfo . fib_DirEntryType == ST_SOFTLINK || FileInfo . fib_DirEntryType == ST_LINKDIR || FileInfo . fib_DirEntryType == ST_LINKFILE;
  2610.             st -> st_uid    = FileInfo . fib_OwnerUID;
  2611.             st -> st_gid    = FileInfo . fib_OwnerGID;
  2612.             st -> st_size    = FileInfo . fib_Size;
  2613.             st -> st_atime    = GMT_Offset + (FileInfo . fib_Date . ds_Days * 24 * 60 + FileInfo . fib_Date . ds_Minute) * 60 + (FileInfo . fib_Date . ds_Tick / TICKS_PER_SECOND);
  2614.             st -> st_mtime    = st -> st_atime;
  2615.             st -> st_ctime    = st -> st_atime;
  2616.             st -> st_type    = FileInfo . fib_DirEntryType;
  2617.             st -> st_comment= Comment;
  2618.  
  2619.                 /* Success. */
  2620.  
  2621.             return(0);
  2622.         }
  2623.  
  2624.         UnLock(FileLock);
  2625.     }
  2626.  
  2627.         /* What else should I choose? */
  2628.  
  2629.     errno = _OSERR = EIO;
  2630.  
  2631.     return(-1);
  2632. }
  2633.